/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package theoriedesjeux;

/**
 * Classe réalisant l'algorithme de Neumann dans la Théorie des jeux
 * @author saluzzo
 */
public class AlgoNeumann {
    /**
     * Matrice de jeux de l'algoritme
     */
    private double[][] matrice;

    /**
     * Constructeur de l'algorithme,
     * Programme principal de l'application
     */
    public AlgoNeumann() {
        System.out.println("Voici notre matrice de jeux de depart: ");

        defineMatriceTest();
        writeMatrix();

        System.out.println();
        
        System.out.println("Determinons la methode a utilisé");
        System.out.println();
        if((miniMax().getValeur() == maxiMin().getValeur()) && (this.haveOneMaxiMin() & this.haveOneMiniMax())) {
            System.out.println("Nous pouvons determiner la strategie otpimale dessuite:");
            System.out.println("La stategie optimal est la stategie A"+maxiMin().getIndex());
        } else {
            System.out.println("Impossible de determiner la strategie optimale dessuite, nous devons effectué un simplex:");
            writeSimplex();
        }
    }

    /**
     * Permet l'affichage des equations du Simplex de la matrice
     */
    public void writeSimplex() {
        for(int i =0; i < matrice[0].length; i++) {
            String temp = new String();
            for(int j =0; j< matrice.length; j++) {
                if(j==0) {
                    temp = temp + matrice[j][i] + ".PA" + j;
                } else {
                    temp = temp + " + " + matrice[j][i] + ".PA" + j;
                }
            }

            temp = temp + " >= g";
            System.out.println(temp);
        }
    }

    /**
     * Permet l'affichage de la matrice de jeux
     */
    public void writeMatrix() {
        for(int i = 0; i < matrice.length; i++) {
            String temp = new String();
            for(int j=0; j < matrice[i].length; j++) {
                temp = temp + "| " + matrice[i][j] + " |";
            }
            System.out.println(temp);
        }
    }

    /**
     * Créer une matrice de jeux de test pour la resolution rapide
     */
    void defineMatriceTestSimple() {
        matrice = new double[4][4];
        matrice[0][0] = 0.3;
        matrice[0][1] = 0;
        matrice[0][2] = 0.5;
        matrice[0][3] = 0.2;

        matrice[1][0] = 0.4;
        matrice[1][1] = 0;
        matrice[1][2] = 0.4;
        matrice[1][3] = 0.3;

        matrice[2][0] = 0.3;
        matrice[2][1] = 0.2;
        matrice[2][2] = 0.2;
        matrice[2][3] = 0.5;

        matrice[3][0] = 0;
        matrice[3][1] = 0.2;
        matrice[3][2] = 0.6;
        matrice[3][3] = 0.4;
    }

    /**
     * créer une matrice de jeux de Test
     */
    void defineMatriceTest() {
        matrice = new double[4][4];
        matrice[0][0] = 0.3;
        matrice[0][1] = 0.1;
        matrice[0][2] = 0.5;
        matrice[0][3] = 0.2;

        matrice[1][0] = 0.4;
        matrice[1][1] = 0.1;
        matrice[1][2] = 0.4;
        matrice[1][3] = 0.3;

        matrice[2][0] = 0.1;
        matrice[2][1] = 0.2;
        matrice[2][2] = 0.2;
        matrice[2][3] = 0.5;

        matrice[3][0] = 0;
        matrice[3][1] = 0.2;
        matrice[3][2] = 0.6;
        matrice[3][3] = 0.4;
    }

    /**
     * retourne une liste des minimums dans la matrice de jeux
     * @param matriceDeJeux matrice de jeux a etudié
     * @return liste des minimums
     */
    public Valeur[] minimum(double[][] matriceDeJeux) {
        Valeur[] resultat = new Valeur[matriceDeJeux.length];
        for(int i =0; i< matriceDeJeux.length; i++) {
            for(int j =0; j< matriceDeJeux[i].length; j++) {
                if(j==0){
                    resultat[i] = new Valeur(i, matriceDeJeux[i][j]);
                } else {
                    if(resultat[i].getValeur() > matriceDeJeux[i][j]) {
                        resultat[i] = new Valeur(i, matriceDeJeux[i][j]);
                    }
                }
            }
        }
        return resultat;
    }

    /**
     * retourne une liste des maximum dans la matrice de jeux
     * @param matriceDeJeux matrice de jeux a etudié
     * @return liste des maximums
     */
    public Valeur[] maximum(double[][] matriceDeJeux) {
        Valeur[] resultat = new Valeur[matriceDeJeux.length];
        for(int i =0; i < matriceDeJeux[0].length; i++) {
            for(int j =0; j< matriceDeJeux.length; j++) {
                if(j==0){
                    resultat[i] = new Valeur(i, matriceDeJeux[j][i]);
                } else {
                    if(resultat[i].getValeur() < matriceDeJeux[j][i]) {
                        resultat[i] = new Valeur(i, matriceDeJeux[j][i]);
                    }
                }
            }
        }
        return resultat;
    }

    /**
     * permet de determiner si il n'y a qu'une seul valeur maximin dans la matrice
     * @return true si il n'y en a qu'une seul, sinon false
     */
    public boolean haveOneMaxiMin() {
        Valeur[] resultat = minimum(matrice);
        Valeur maximin = getMax(resultat);
        int count = 0;
        for(int i=0; i < resultat.length; i++) {
            if(resultat[i].getValeur() == maximin.getValeur()) {
                count++;
            }
        }

        if(count > 1) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * permet de determiner si il n'y a qu'une seul valeur minimax dans la matrice
     * @return true si il n'y en a qu'une seul, sinon false
     */
    public boolean haveOneMiniMax() {
        Valeur[] resultat = maximum(matrice);
        Valeur minimax = getMin(resultat);
        int count = 0;
        for(int i=0; i < resultat.length; i++) {
            if(resultat[i].getValeur() == minimax.getValeur()) {
                count++;
            }
        }
        if(count > 1) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * Retourne les valeurs maximales de la matrice de jeux donnée en parametre
     * @param resultat morceau de matrice de jeux
     * @return retourne un tableau de valeurs maximales
     */
    public Valeur[] getMaxs(Valeur[] resultat) {
        Valeur maximin = getMax(resultat);
        int count = 0;
        for(int i=0; i < resultat.length; i++) {
            if(resultat[i].getValeur() == maximin.getValeur()) {
                count++;
            }
        }
        Valeur[] maxs = new Valeur[count];
        for(int i=0; i < count; i++) {
            if(resultat[i].getValeur() == maximin.getValeur()) {
                maxs[i] = resultat[i];
            }
        }

        return maxs;
    }

    /**
     * Retourne les valeurs minimales de la matrice de jeux donnée en parametre
     * @param resultat morceau de matrice de jeux
     * @return retourne un tableau de valeurs minimales
     */
    public Valeur[] getMins(Valeur[] resultat) {
        Valeur minimax = getMin(resultat);
        int count = 0;
        for(int i=0; i < resultat.length; i++) {
            if(resultat[i].getValeur() == minimax.getValeur()) {
                count++;
            }
        }
        Valeur[] mins = new Valeur[count];
        for(int i=0; i < count; i++) {
            if(resultat[i].getValeur() == minimax.getValeur()) {
                mins[i] = resultat[i];
            }
        }

        return mins;
    }

    /**
     * Retourne la valeur minimale la matrice de jeux donné en parametre
     * @param matriceDeJeux morceau de matrice de jeux
     * @return la valeur minimale dans un objet Valeur
     */
    public Valeur getMin(Valeur[] matriceDeJeux) {
        Valeur resultat = null;
        for(int j =0; j< matriceDeJeux.length; j++) {
            if(j == 0){
                resultat = matriceDeJeux[j];
            } else {
                if(resultat.getValeur() > matriceDeJeux[j].getValeur()) {
                    resultat = matriceDeJeux[j];
                }
            }
        }
        return resultat;
    }

    /**
     * Retourne la valeur maximale la matrice de jeux donné en parametre
     * @param matriceDeJeux morceau de matrice de jeux
     * @return la valeur maximale dans un objet Valeur
     */
    public Valeur getMax(Valeur[] matriceDeJeux) {
        Valeur resultat = null;
        for(int j =0; j< matriceDeJeux.length; j++) {
            if(j == 0){
                resultat = matriceDeJeux[j];
            } else {
                if(resultat.getValeur() < matriceDeJeux[j].getValeur()) {
                    resultat = matriceDeJeux[j];
                }
            }
        }
        return resultat;
    }

    /**
     * retourne la valeur miniMax de la matrice en cours
     * @return un objet Valeur contenant l'index de la valeur ainsi que celle ci
     */
    public Valeur miniMax() {
        return getMin(maximum(matrice));
    }

    /**
     * retourne la valeur maxiMin de la matrice en cours
     * @return un objet Valeur contenant l'index de la valeur ainsi que celle ci
     */
    public Valeur maxiMin() {
        return getMax(minimum(matrice));
    }
}
